package edu.luc.cs.trull.task;

import EDU.oswego.cs.dl.util.concurrent.Executor;
import EDU.oswego.cs.dl.util.concurrent.QueuedExecutor;
import org.apache.log4j.Logger;

/**
 * A Worker that uses a single-threaded QueuedExecutor to perform its Task.
 */
public class QueuedTaskWorker extends AbstractTaskWorker {

  private static Logger logger = Logger.getLogger(QueuedTaskWorker.class);

  private final static Executor executor = new QueuedExecutor();

  protected final Executor getExecutor() { return executor; }

  public QueuedTaskWorker(final Task task) {
    super(task);
    setStart(new Runnable() {
      public void run() {
        logger.debug(QueuedTaskWorker.this +".start.run()");
        try {
          if (state.get() == STOPPED) return;
          // don't need firstTime to be synched?
          if (!firstTime.commit(true, false)) {
            logger.debug(QueuedTaskWorker.this +".start.run() restarting task");
            task.restart();
          }
          synchronized (state.getLock()) {
            state.whenLess(SUSPENDED, null);
            if (state.get() == STOPPED) return;
          }
          executor.execute(repeat);
        } catch (InterruptedException e) {
          logger.debug(QueuedTaskWorker.this +".start.run() interrupted, returning");
          Thread.currentThread().interrupt();
        } finally {
          logger.debug(QueuedTaskWorker.this +".start.run() returning");
        }
      }
    });
  }

  private final Runnable repeat = new Runnable() {
    public void run() {
      try {
        logger.debug(QueuedTaskWorker.this +".repeat.run()");
        if (state.get() == STOPPED) return;
        if (task.hasNext()) {
          task.next();
          synchronized (state.getLock()) {
            state.whenLess(SUSPENDED, null);
            if (state.get() == STOPPED) return;
            executor.execute(repeat);
          }
        } else {
          logger.debug(QueuedTaskWorker.this +".repeat.run() finishing");
          state.set(STOPPED);
          finish.run();
        }
      } catch (InterruptedException e) {
        logger.debug(QueuedTaskWorker.this +".repeat.run() interrupted, returning");
        Thread.currentThread().interrupt();
      } finally {
        logger.debug(QueuedTaskWorker.this +".repeat.run() returning");
      }
    }
  };
}